﻿using System;
using System.Diagnostics.Contracts;
using System.Globalization;

namespace OpenWaves.ImageTransformations
{
    public abstract class ImageTransformation : IImageTransformation, IResponsiveImageTransformation
    {
        public static readonly IImageTransformation Null = new NullTransformation();

        public static bool TryParse(string value, out IImageTransformation transformation)
        {
            return ServiceLocator.Resolve<IImageTransformationParser>().TryParse(value, out transformation);
        }

        public static IImageTransformation Parse(string value)
        {
            return ServiceLocator.Resolve<IImageTransformationParser>().Parse(value);
        }

        private readonly int width;
        public int Width
        {
            get { return this.width; }
        }

        private readonly int height;
        public int Height
        {
            get { return this.height; }
        }

        protected ImageTransformation(int width, int height)
        {
            Contract.Requires<ArgumentNullException>(width > 0);
            Contract.Requires<ArgumentNullException>(height > 0);

            this.width = width;
            this.height = height;
        }

        protected ImageTransformation(string serializedProperties)
        {
            Contract.Requires<ArgumentNullException>(String.IsNullOrEmpty(serializedProperties) == false);

            var dimensions = serializedProperties.Split('x');
            Contract.Assert(dimensions.Length == 2);

            this.width = Int32.Parse(dimensions[0], CultureInfo.InvariantCulture);
            this.height = Int32.Parse(dimensions[1], CultureInfo.InvariantCulture);
        }

        public abstract void ApplyToImage(IImage image);

        public string Serialize()
        {
            Contract.Assert(this.GetType().Name.EndsWith("Transformation", StringComparison.Ordinal));

            var s = this.GetType().Name;
            var name = s.Substring(0, s.Length - "Transformation".Length);
            return String.Format(CultureInfo.InvariantCulture, "{0}:{1}x{2}", name, this.Width, this.Height);
        }

        public override string ToString()
        {
            return this.Serialize();
        }

        public bool Equals(ImageTransformation other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.width == this.width && other.height == this.height;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((ImageTransformation)obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return (this.width * 397) ^ this.height;
            }
        }

        public IImageTransformation Scale(double pixelRatio)
        {
            return this.Scale((int) (this.Width*pixelRatio), (int) (this.Height*pixelRatio));
        }

        protected abstract IImageTransformation Scale(int width, int height);

        private class NullTransformation : IImageTransformation
        {
            public void ApplyToImage(IImage image)
            {
            }

            public string Serialize()
            {
                return "Null";
            }
        }
    }
}